Fixed relocation types and added GOT supports. Change-Id: I7803a4f6a52a237b16c67adc09948705d4fc5533 
diff --git a/Android.mk b/Android.mk index c1d41d2..014ef83 100644 --- a/Android.mk +++ b/Android.mk 
@@ -35,6 +35,7 @@  lib/ELFTypes.cpp \  lib/MemChunk.cpp \  lib/StubLayout.cpp \ + lib/GOT.cpp \  utils/raw_ostream.cpp \  utils/rsl_assert.cpp \  utils/helper.cpp \ 
diff --git a/SConstruct b/SConstruct index 03a47d3..1fa5b63 100644 --- a/SConstruct +++ b/SConstruct 
@@ -94,6 +94,7 @@  'lib/ELFTypes.cpp',  'lib/MemChunk.cpp',  'lib/StubLayout.cpp', + 'lib/GOT.cpp',  'utils/helper.cpp',  'utils/raw_ostream.cpp',  'utils/rsl_assert.cpp', 
diff --git a/include/GOT.h b/include/GOT.h new file mode 100644 index 0000000..8489b29 --- /dev/null +++ b/include/GOT.h 
@@ -0,0 +1,37 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef GOT_H +#define GOT_H + +#include "utils/rsl_assert.h" +#include "ELF.h" + +#if defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) +#define GP_OFFSET	((int)0x8000) +#define GOT_SIZE	(1 << 16)	// bytes +#define GOT_ENTRY_SIZE	4	// bytes +#define NUM_OF_GOT_ENTRY	(GOT_SIZE/GOT_ENTRY_SIZE) +#else +#define GOT_SIZE	4	// bytes +#define GOT_ENTRY_SIZE	4	// bytes +#define NUM_OF_GOT_ENTRY	(GOT_SIZE/GOT_ENTRY_SIZE) +#endif + +void *got_address(); +int search_got(int symbol_index, void *addr, uint8_t bind_type); + +#endif // GOT_H 
diff --git a/include/impl/ELFObject.hxx b/include/impl/ELFObject.hxx index 83a1bc6..e491e15 100644 --- a/include/impl/ELFObject.hxx +++ b/include/impl/ELFObject.hxx 
@@ -22,6 +22,7 @@  #include "ELFSection.h"  #include "ELFSectionHeaderTable.h"  #include "StubLayout.h" +#include "GOT.h"  #include "ELF.h"    #include <llvm/ADT/SmallVector.h> @@ -370,7 +371,10 @@  Inst_t A = (Inst_t)(uintptr_t)*inst;  Inst_t S = (Inst_t)(uintptr_t)sym->getAddress();   - if (S == 0) { + bool need_stub = false; + + if (S == 0 && strcmp (sym->getName(), "_gp_disp") != 0) { + need_stub = true;  S = (Inst_t)(uintptr_t)find_sym(context, sym->getName());  sym->setAddress((void *)S);  } @@ -380,31 +384,98 @@  rsl_assert(0 && "Not implemented relocation type.");  break;   - case R_MIPS_HI16: - A = A & 0xFFFF; - // FIXME: We just support addend = 0. - rsl_assert(A == 0 && "R_MIPS_HI16 addend is not 0."); - *inst |= (((S + 0x8000) >> 16) & 0xFFFF); + case R_MIPS_NONE: + case R_MIPS_JALR: // ignore this  break;   - case R_MIPS_LO16: + case R_MIPS_16: + *inst &= 0xFFFF0000;  A = A & 0xFFFF; - // FIXME: We just support addend = 0. - rsl_assert(A == 0 && "R_MIPS_LO16 addend is not 0."); - *inst |= (S & 0xFFFF); - break; - - case R_MIPS_26: - A = A & 0x3FFFFFF; - // FIXME: We just support addend = 0. - rsl_assert(A == 0 && "R_MIPS_26 addend is not 0."); - *inst |= ((S >> 2) & 0x3FFFFFF); - rsl_assert((((P + 4) >> 28) != (S >> 28)) && "Cannot relocate R_MIPS_26 due to differences in the upper four bits."); + A = S + (short)A; + rsl_assert(A >= -32768 && A <= 32767 && "R_MIPS_16 overflow."); + *inst |= (A & 0xFFFF);  break;    case R_MIPS_32:  *inst = S + A;  break; + + case R_MIPS_26: + *inst &= 0xFC000000; + if (need_stub == false) { + A = (A & 0x3FFFFFF) << 2; + if (sym->getBindingAttribute() == STB_LOCAL) { // local binding + A |= ((P + 4) & 0xF0000000); + A += S; + *inst |= ((A >> 2) & 0x3FFFFFF); + } + else { // external binding + if (A & 0x08000000) // Sign extend from bit 27 + A |= 0xF0000000; + A += S; + *inst |= ((A >> 2) & 0x3FFFFFF); + if (((P + 4) >> 28) != (A >> 28)) { // far local call + void *stub = text->getStubLayout()->allocateStub((void *)A); + rsl_assert(stub && "cannot allocate stub."); + sym->setAddress(stub); + S = (int32_t)stub; + *inst |= ((S >> 2) & 0x3FFFFFF); + rsl_assert(((P + 4) >> 28) == (S >> 28) && "stub is too far."); + } + } + } + else { // shared-library call + A = (A & 0x3FFFFFF) << 2; + rsl_assert(A == 0 && "R_MIPS_26 addend is not zero."); + void *stub = text->getStubLayout()->allocateStub((void *)S); + rsl_assert(stub && "cannot allocate stub."); + sym->setAddress(stub); + S = (int32_t)stub; + *inst |= ((S >> 2) & 0x3FFFFFF); + rsl_assert(((P + 4) >> 28) == (S >> 28) && "stub is too far."); + } + break; + + case R_MIPS_HI16: + *inst &= 0xFFFF0000; + A = A & 0xFFFF; + if (strcmp (sym->getName(), "_gp_disp") == 0) { + S = (int)got_address() + GP_OFFSET - (int)P; + sym->setAddress((void *)S); + } + *inst |= (((S + (A << 16) + (int)0x8000) >> 16) & 0xFFFF); + break; + + case R_MIPS_LO16: + *inst &= 0xFFFF0000; + A = A & 0xFFFF; + if (strcmp (sym->getName(), "_gp_disp") == 0) { + S = (Inst_t)sym->getAddress(); + } + *inst |= ((S + A) & 0xFFFF); + // We assume the addend of R_MIPS_LO16 won't affect R_MIPS_HI16. + // If not, we have troubles. + if (((S + (short)A + (int)0x8000) >> 16) != ((S + (int)0x8000) >> 16)) + rsl_assert("AHL cannot be calculated correctly."); + break; + + case R_MIPS_GOT16: + case R_MIPS_CALL16: + { + *inst &= 0xFFFF0000; + A = A & 0xFFFF; + // FIXME: We just support addend = 0. + rsl_assert(A == 0 && "R_MIPS_GOT16/R_MIPS_CALL16 addend is not 0."); + int got_index = search_got((int)rel->getSymTabIndex(), (void *)S, + sym->getBindingAttribute()); + int got_offset = (got_index << 2) - GP_OFFSET; + *inst |= (got_offset & 0xFFFF); + } + break; + + case R_MIPS_GPREL32: + *inst = A + S - ((int)got_address() + GP_OFFSET); + break;  }  }  } 
diff --git a/include/impl/ELFSectionRelTable.hxx b/include/impl/ELFSectionRelTable.hxx index e83799c..4c2417d 100644 --- a/include/impl/ELFSectionRelTable.hxx +++ b/include/impl/ELFSectionRelTable.hxx 
@@ -93,7 +93,7 @@  switch (obj->getHeader()->getMachine()) {  case EM_ARM:  { - std::set<word_t> sym_index_set; + std::set<uint32_t> sym_index_set;    for (size_t i = 0; i < size(); ++i) {  ELFRelocTy *rel = table[i]; @@ -106,9 +106,23 @@  return sym_index_set.size();  }   + case EM_MIPS: + { + std::set<uint32_t> sym_index_set; + + for (size_t i = 0; i < size(); ++i) { + ELFRelocTy *rel = table[i]; + + if (rel->getType() == R_MIPS_26) { + sym_index_set.insert(rel->getSymTabIndex()); + } + } + + return sym_index_set.size(); + } +  case EM_386:  case EM_X86_64: - case EM_MIPS:  return 0;    default: 
diff --git a/include/impl/ELFSymbol.hxx b/include/impl/ELFSymbol.hxx index 176428a..01c84cc 100644 --- a/include/impl/ELFSymbol.hxx +++ b/include/impl/ELFSymbol.hxx 
@@ -199,8 +199,12 @@  }  break;   - case SHN_ABS:  case SHN_UNDEF: +#if defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) + if (strcmp(getName(), "_gp_disp") == 0) // OK for MIPS + break; +#endif + case SHN_ABS:  case SHN_XINDEX:  rsl_assert(0 && "STT_OBJECT with special st_shndx.");  break; 
diff --git a/lib/GOT.cpp b/lib/GOT.cpp new file mode 100644 index 0000000..fbafaea --- /dev/null +++ b/lib/GOT.cpp 
@@ -0,0 +1,74 @@ +/* + * Copyright 2011, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdio.h> +#include "GOT.h" + +void *got_symbol_addresses[NUM_OF_GOT_ENTRY]; +int got_symbol_indexes[NUM_OF_GOT_ENTRY]; +size_t got_symbol_count = 0; + +void *got_address() +{ + return &got_symbol_addresses[0]; +} + +#if defined(mips) || defined(__mips__) || defined(MIPS) || defined(_MIPS_) + +int search_got(int symbol_index, void *addr, uint8_t bind_type) +{ + size_t i; + + // For local symbols (R_MIPS_GOT16), we only store the high 16-bit value + // after adding 0x8000. + if (bind_type == STB_LOCAL) + addr = (void *)(((int)addr + 0x8000) & 0xFFFF0000); + + for (i = 0; i < got_symbol_count; i++) { + if (got_symbol_indexes[i] == symbol_index) { + if (bind_type == STB_LOCAL) { + // Check if the value is the same for local symbols. + // If yes, we can reuse this entry. + // If not, we continue searching. + if (got_symbol_addresses[i] == addr) { + return i; + } + } + else { + // The value must be the same for global symbols . + rsl_assert (got_symbol_addresses[i] == addr + && "MIPS GOT address error."); + return i; + } + } + } + + // Cannot find this symbol with correct value, so we need to create one + rsl_assert (got_symbol_count < NUM_OF_GOT_ENTRY && "MIPS GOT is full."); + got_symbol_indexes[got_symbol_count] = symbol_index; + got_symbol_addresses[got_symbol_count] = addr; + got_symbol_count++; + return (got_symbol_count - 1); +} + +#else + +int search_got(int symbol_index, void *addr, uint8_t bind_type) +{ + return 0; +} + +#endif